package com.liuya.safe.policy.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.liuya.base.BaseController;
import com.liuya.common.SpringUtils;
import com.liuya.common.WebUtil;
import com.liuya.safe.util.AuthUtil;
import com.liuya.safe.util.Constants;
import com.liuya.safe.exception.AuthException;
import com.liuya.safe.policy.handler.AbstractPolicyDesignHandler;
import com.liuya.safe.policy.service.QueryManagerService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.liuya.db.sql.xml.ContextValue;
import com.liuya.db.sql.xml.DefineVariable;
import com.liuya.db.sql.xml.Formula;
import com.liuya.db.sql.xml.HintValue;
import com.liuya.db.sql.xml.QueryRef;
import com.liuya.db.sql.xml.SimpleValue;
import com.liuya.db.sql.xml.UserValue;
import com.liuya.db.sql.xml.Variable;
import com.liuya.db.sql.xml.types.FormulaTypeOperatorType;
import com.liuya.db.sql.xml.types.FormulaTypeTypeType;
import com.liuya.db.sql.xml.types.SimpleValueTypeTypeType;
import org.springframework.ui.ModelMap;

public abstract class AbstractPolicyRawController extends BaseController {

    private static final Log log = LogFactory.getLog(AbstractPolicyRawController.class);

    public Object rawPolicy(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        return handler.getRawMainPage();
    }

    public Object designVariables(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        DefineVariable[] variables = handler.getVariables();
        req.setAttribute("variables", variables);

        return handler.getVariablesPage();
    }

    public Object getVariable(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        DefineVariable[] variables = handler.getVariables();
        int index = WebUtil.getIntParameter(req, "index", 0);

        DefineVariable var = variables[index];

        String[] userFields = AuthUtil.getUserType(req).getUserMetadata().getUserFields();
//        req.setAttribute("userFields", ReflectUtil.reflectJavaBeanFieldNames(SafeUser.class).toArray());
        req.setAttribute("userFields", userFields);
        req.setAttribute("variable", var);

        return getVariableDefinePage(var);
    }

    public Object newVariable(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        String[] userFields = AuthUtil.getUserType(req).getUserMetadata().getUserFields();
//        req.setAttribute("userFields", ReflectUtil.reflectJavaBeanFieldNames(SafeUser.class).toArray());
        req.setAttribute("userFields", userFields);

        return getVariableDefinePage(req);
    }

    public Object returnMain(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);
        // remove handler from session
        req.getSession().removeAttribute(getPolicyHandlerAttributeKey(req));

        return "redirect:/" + handler.getManagePage();
    }

    public Object deleteVariable(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        handler.deleteVariable(WebUtil.getIntParameter(req, "index", 0));
        updateHandler(req, handler);
        return true;
    }

    public Object addVariable(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        DefineVariable var = getDefineVariable(req);

        handler.addVariable(var);
        updateHandler(req, handler);

        return true;
    }

    public Object updateVariable(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        DefineVariable var = getDefineVariable(req);

        int varIndex = WebUtil.getIntParameter(req, "index", -1);
        handler.updateVariable(varIndex, var);
        updateHandler(req, handler);
        return true;
    }

    public Object save(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        // remove handler from session
        req.getSession().removeAttribute(getPolicyHandlerAttributeKey(req));

        String id = WebUtil.getStringParameter(req, "id", "-23");
        boolean result = handler.save(id);
        updateHandler(req, handler);
        return result;
    }

    public Object setRawScript(HttpServletRequest req, HttpServletResponse rep, ModelMap modelMap){
        String oper = req.getParameter("oper");
        AbstractPolicyDesignHandler handler = getPolicyHandler(req);
        req.setAttribute("handler", handler);

        String script = req.getParameter("rawScript");
        handler.setRawScript(script);
        updateHandler(req, handler);
        return true;
    }

    public abstract AbstractPolicyDesignHandler createPolicyHandler(HttpServletRequest req);

    public abstract String getPolicyHandlerAttributeKey(HttpServletRequest req);

    private AbstractPolicyDesignHandler getPolicyHandler(HttpServletRequest req) {
        String oper = req.getParameter("oper");
        String key = getPolicyHandlerAttributeKey(req);
        AbstractPolicyDesignHandler handler = (AbstractPolicyDesignHandler) req.getSession().getAttribute(key);

        if (handler == null || "loadFresh".equals(oper)) {
            handler = createPolicyHandler(req);

            // save into session, will be removed when policy is saved
            req.getSession().setAttribute(key, handler);
        }

        handler.setRawMode();

        return handler;
    }

    private String getVariableDefinePage(HttpServletRequest req) {
        String varType = req.getParameter("type");

        if ("contextValue".equals(varType)) {
            return "policy/common/contextValue";
        } else if ("formula".equals(varType)) {
            return "policy/common/formula";
        } else if ("hintValue".equals(varType)) {
            return "policy/common/businessData";
        } else if ("query".equals(varType)) {
            return "policy/common/queryRef";
        } else if ("simpleValue".equals(varType)) {
            return "policy/common/simpleValue";
        } else if ("userValue".equals(varType)) {
            return "policy/common/userValue";
        } else if ("hintValue".equals(varType)) {
            return "policy/common/businessData";
        } else {
            throw new AuthException("Unknown variable type");
        }
    }

    private String getVariableDefinePage(DefineVariable var) {
        if (var.getContextValue() != null) {
            return "policy/common/contextValue";
        } else if (var.getFormula() != null) {
            return "policy/common/formula";
        } else if (var.getHintValue() != null) {
            return "policy/common/businessData";
        } else if (var.getQueryRef() != null) {
            return "policy/common/queryRef";
        } else if (var.getSimpleValue() != null) {
            return "policy/common/simpleValue";
        } else if (var.getUserValue() != null) {
            return "policy/common/userValue";
        } else {
            throw new AuthException("Unknown variable type");
        }
    }

    private DefineVariable getDefineVariable(HttpServletRequest req) {
        String type = req.getParameter("type");
        String name = req.getParameter("name");

        DefineVariable var = new DefineVariable();
        var.setName(name);

        if ("userValue".equals(type)) {
            String key = req.getParameter("key");

            UserValue userValue = new UserValue();
            userValue.setKey(key);

            var.setUserValue(userValue);
        } else if ("simpleValue".equals(type)) {
            String content = req.getParameter("content");
            String stype = req.getParameter("stype");
            SimpleValue value = new SimpleValue();
            value.setContent(content);
            value.setType(SimpleValueTypeTypeType.valueOf(stype));

            var.setSimpleValue(value);
        } else if ("contextValue".equals(type)) {
            String key = req.getParameter("key");

            ContextValue value = new ContextValue();
            value.setKey(key);

            var.setContextValue(value);
        } else if ("hintValue".equals(type)) {
            String key = req.getParameter("key");

            HintValue value = new HintValue();
            value.setKey(key);
            value.setHint(Constants.BUSINESS_DATA);

            var.setHintValue(value);
        } else if ("formula".equals(type)) {
            String operName1 = req.getParameter("operName1");
            String operName2 = req.getParameter("operName2");
            String operator = req.getParameter("operator");
            String returnType = req.getParameter("returnType");

            Variable var0 = new Variable();
            var0.setName(operName1);
            Variable var1 = new Variable();
            var1.setName(operName2);

            Formula value = new Formula();

            value.addVariable(var0);
            value.addVariable(var1);
            value.setOperator(FormulaTypeOperatorType.valueOf(operator));
            value.setType(FormulaTypeTypeType.valueOf(returnType));
            var.setFormula(value);
        } else if ("queryRef".equals(type)) {
            String id = WebUtil.getStringParameter(req, "queryId", "-999");
            QueryManagerService mng = (QueryManagerService) SpringUtils.getBean("queryManagerService");
            String queryName = mng.getQuery(id).getName();

            QueryRef value = new QueryRef();
            value.setId(id);
            value.setName(queryName);

            var.setQueryRef(value);
        }

        return var;
    }

    protected abstract void updateHandler(HttpServletRequest req, Object handler);

}
